package com.boyaa.lxc.common;

import android.content.Context;
import android.graphics.Canvas;
import android.os.SystemClock;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;

public class CanvasSurfaceView extends SurfaceView implements Callback {
	private static final String TAG = "CanvasSurfaceView";
	private boolean mSizeChanged = true;
	
	
	private SurfaceHolder mHolder;
	private CanvasThread mCanvasThread;

	public CanvasSurfaceView(Context context) {
		super(context);
		init();
	}

	private void init(){
		mHolder = getHolder();
		mHolder.addCallback(this);
		mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
	}
	
	public SurfaceHolder getSurfaceHolder(){
		return mHolder;
	}
	
	public void setRenderer(Renderer renderer){
		mCanvasThread = new CanvasThread(mHolder,renderer);
		mCanvasThread.start();
	}
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		mCanvasThread.onWindowResize(width,height);
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		mCanvasThread.surfaceCreated();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		mCanvasThread.surfaceDestroyed();

	}
	
	/** Inform the view that the activity is paused.*/
	public void onPause(){
		mCanvasThread.onPause();
	}
	
	public void onResume(){
		mCanvasThread.onResume();
	}
	
	public void onWindowFocusChanged(boolean hasFocus){
		super.onWindowFocusChanged(hasFocus);
		mCanvasThread.onWindowFocusChanged(hasFocus);
	}
	
	public void setEvent(Runnable r){
		mCanvasThread.setEvent(r);
	}
	
	public void clearEvent(){
		mCanvasThread.clearEvent();
	}
	
	public void stopDrawing(){
		mCanvasThread.requestExitAndWait();
	}
	
	
	@Override
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		mCanvasThread.requestExitAndWait();
	}


	public interface Renderer{
		
		void sizeChanged(int width,int height);
		void drawFrame(Canvas canvas,int sum,int rate,long sleep);
	}
	
	
	public static int PER_FRAME_TIME = 33;   //每一帧的时间（ms）
	private long frameTime = 0;
	private int frameSum = 0;
	private int frameRate = 0;
	private int currentFrameRate = 0;
	private long sleepMs = 0;
	
	class CanvasThread extends Thread{

		private boolean mDone;
		private boolean mPaused;
		private boolean mHasFocus;
		private boolean mHasSurface;
		private boolean mContextLost;
		private int mWidth;
		private int mHeight;
		private Renderer mRenderer;
		private Runnable mEvent;
		private SurfaceHolder mSurfaceHolder;
		
		public CanvasThread(SurfaceHolder mHolder, Renderer renderer) {
			super();
			mDone = false;
			mWidth = 0;
			mHeight = 0;
			mRenderer = renderer;
			mSurfaceHolder = mHolder;
			setName("CanvasThread");
			frameSum = 0;
		}
		
		@Override
		public void run() {
			boolean tellRendererSurfaceChanged = true;
			
			while(!mDone){
				
				int w;
				int h;
				
				synchronized(this){
					if(mEvent != null){
						mEvent.run();
					}
					
					while(needToWait()){
						try {
							wait();
						} catch (InterruptedException e) {
							
						}
					}
					
					if(mDone){
						break;
					}
					
					tellRendererSurfaceChanged = mSizeChanged;
					w = mWidth;
					h = mHeight;
					mSizeChanged = false;
				}
				
				if(tellRendererSurfaceChanged){
					mRenderer.sizeChanged(w, h);
					tellRendererSurfaceChanged = false;
				}
				
				if( w >0 && h > 0){
					long currentTime = SystemClock.uptimeMillis();
					Log.d(TAG, "currentTime(uptimeMillis)="+currentTime);
					frameSum++;
					frameRate++;
					if(currentTime - frameTime > 1000){
						frameTime = currentTime;
						currentFrameRate = frameRate;
						frameRate = 0;
					}
					
					Canvas canvas = mSurfaceHolder.lockCanvas();
					if(canvas != null){
						mRenderer.drawFrame(canvas, frameSum, currentFrameRate, sleepMs);
						mSurfaceHolder.unlockCanvasAndPost(canvas);
					}
					
					currentTime = SystemClock.uptimeMillis() - currentTime;
					if( currentTime < PER_FRAME_TIME){
						sleepMs = PER_FRAME_TIME - currentTime;
					}
					SystemClock.sleep(sleepMs);
				}
			}
			
		}
		
		private boolean needToWait(){
			return (mPaused || (!mHasFocus) || (!mHasSurface) || mContextLost)
					&& (!mDone);
		}
		
		public void surfaceCreated(){
			synchronized(this){
				mHasSurface = true;
				mContextLost = false;
				notify();
			}
		}
		
		public void surfaceDestroyed(){
			synchronized(this){
				mHasSurface = false;
				notify();
			}
		}
	
		public void onPause(){
			synchronized(this){
				mPaused = true;
			}
		}
		
		public void onResume(){
			synchronized(this){
				mPaused = false;
				notify();
			}
		}
		
		public void onWindowFocusChanged(boolean hasFocus){
			synchronized(this){
				//mHasFocus = hasFocus;
				mHasFocus = true; //force to true
				if(mHasFocus == true){
					notify();
				}
			}
		}
		
		public void onWindowResize(int w,int h){
			synchronized(this){
				mWidth = w;
				mHeight = h;
				mSizeChanged = true;
			}
		}
		
		public void requestExitAndWait(){
			//don't call this from CanvasThread thread or it is a guaranteed
			//deadlock!
			synchronized(this){
				mDone = true;
				notify();
			}
			try {
				join();
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
			}
		}
		
		public void setEvent(Runnable r){
			synchronized(this){
				mEvent = r;
			}
		}
		
		public void clearEvent(){
			synchronized(this){
				mEvent = null;
			}
		}
		
	}

}
